/*
实验11-4 笛卡尔树
分数 25
作者 DS课程组
单位 浙江大学

笛卡尔树是一种特殊的二叉树，其结点包含两个关键字 k1​ 和 k2​。
首先笛卡尔树是关于 k1​ 的二叉查找树，即结点左子树的所有 k1​ 值都比该结点的 k1​ 值小，右子树则大。
其次所有结点的 k2​ 关键字满足优先队列（不妨设为最小堆）的顺序要求，即该结点的 k2​ 值比其子树中所有结点的 k2​ 值小。
给定一棵二叉树，请判断该树是否笛卡尔树。

输入格式:

输入首先给出正整数 n（≤1000），为树中结点的个数。随后 n 行，每行给出一个结点的信息，
包括：结点的 k1​ 值、k2​ 值、左孩子结点编号、右孩子结点编号。设结点从0~(n−1)顺序编号。
若某结点不存在孩子结点，则该位置给出 −1。

输出格式:

输出YES如果该树是一棵笛卡尔树；否则输出NO。

输入样例1:

6
8 27 5 1
9 40 -1 -1
10 20 0 3
12 21 -1 4
15 22 -1 -1
5 35 -1 -1

输出样例1:

YES

输入样例2:

6
8 27 5 1
9 40 -1 -1
10 20 0 3
12 11 -1 4
15 22 -1 -1
50 35 -1 -1

输出样例2:

NO
*/

/*
解题思路：

    笛卡尔树的性质：

        笛卡尔树是关于 k1 的二叉查找树，即结点左子树的所有 k1 值都比该结点的 k1 值小，右子树则大。

        笛卡尔树的性质是关于 k2 的优先队列，即该结点的 k2 值比其子树中所有结点的 k2 值小。

    递归构建树：

        我们可以通过递归的方式，根据输入的结点信息构建笛卡尔树。

        在构建过程中，如果发现序列不符合笛卡尔树的性质，则说明该树不是笛卡尔树。

    递归判断性质：

        递归判断笛卡尔树的性质时，我们需要传入两个参数：根结点的 k1 和 k2 的值。

        对于左子树，k1 的值应该小于根结点的 k1 值，k2 的值应该小于根结点的 k2 值。

        对于右子树，k1 的值应该大于根结点的 k1 值，k2 的值应该小于根结点的 k2 值。

        如果左子树或右子树不满足笛卡尔树的性质，则说明该树不是笛卡尔树。

    递归判断性质时，需要注意的是，如果左子树或右子树为空，则不需要判断性质。
*/

#include <iostream>
#include <vector>
#include <climits>

using namespace std;

struct TreeNode {
    int k1, k2;
    int left, right;
};

bool isCartesianTree(const vector<TreeNode> &nodes, int root, int minK1, int maxK1) {
    if (root == -1)
        return true;

    if (nodes[root].k1 < minK1 || nodes[root].k1 > maxK1)
        return false;

    if (nodes[root].left != -1 && nodes[nodes[root].left].k2 < nodes[root].k2)
        return false;

    if (nodes[root].right != -1 && nodes[nodes[root].right].k2 < nodes[root].k2)
        return false;

    return isCartesianTree(nodes, nodes[root].left, minK1, nodes[root].k1) &&
           isCartesianTree(nodes, nodes[root].right, nodes[root].k1, maxK1);
}

int findRoot(const vector<TreeNode> &nodes) {
    vector<bool> isChild(nodes.size(), false);
    for (int i = 0; i < nodes.size(); ++i) {
        if (nodes[i].left != -1)
            isChild[nodes[i].left] = true;
        if (nodes[i].right != -1)
            isChild[nodes[i].right] = true;
    }

    for (int i = 0; i < nodes.size(); ++i) {
        if (!isChild[i])
            return i;
    }

    return -1;
}

int main() {
    int n;
    cin >> n;
    vector<TreeNode> nodes(n);
    for (int i = 0; i < n; ++i) {
        cin >> nodes[i].k1 >> nodes[i].k2 >> nodes[i].left >> nodes[i].right;
    }
    int root = findRoot(nodes);
    if (isCartesianTree(nodes, root, INT_MIN, INT_MAX))
        cout << "YES" << endl;
    else
        cout << "NO" << endl;

    return 0;
}